﻿using System;
using System.Collections;
using System.Collections.Generic;
using Pfz.Collections;

namespace Pfz.RemoteGaming
{
	/// <summary>
	/// Dictionary of components changes.
	/// </summary>
	public sealed class RemoteGameComponentChanges:
		IReadOnlyDictionary<RemoteGameComponent, RemoteGamePropertyChanges>
	{
		private Dictionary<RemoteGameComponent, RemoteGamePropertyChanges> _dictionary = new Dictionary<RemoteGameComponent,RemoteGamePropertyChanges>();
		internal RemoteGameComponentChanges()
		{
		}

		#region Public
			/// <summary>
			/// Gets the components that are in this dictionary.
			/// </summary>
			public ICollection<RemoteGameComponent> Keys
			{
				get
				{
					return _dictionary.Keys;
				}
			}

			/// <summary>
			/// Gets the PropertyChanges that are in this dictionary.
			/// </summary>
			public ICollection<RemoteGamePropertyChanges> Values
			{
				get
				{
					return _dictionary.Values;
				}
			}

			/// <summary>
			/// Gets the changes for a given component.
			/// </summary>
			public RemoteGamePropertyChanges this[RemoteGameComponent key]
			{
				get
				{
					return _dictionary[key];
				}
			}

			/// <summary>
			/// Checks if a component is in this dictionary.
			/// </summary>
			public bool ContainsKey(RemoteGameComponent key)
			{
				return _dictionary.ContainsKey(key);
			}

			/// <summary>
			/// Checks if a PropertyChanges is in this dictionary.
			/// </summary>
			public bool ContainsValue(RemoteGamePropertyChanges value)
			{
				return _dictionary.ContainsValue(value);
			}

			/// <summary>
			/// Tries to get the changes for a given component.
			/// </summary>
			public bool TryGetValue(RemoteGameComponent key, out RemoteGamePropertyChanges value)
			{
				return _dictionary.TryGetValue(key, out value);
			}

			/// <summary>
			/// Gets the number of items in this dictionary.
			/// </summary>
			public int Count
			{
				get
				{
					return _dictionary.Count;
				}
			}

			/// <summary>
			/// Get an enumerator for all items in this dictionary.
			/// </summary>
			public IEnumerator<KeyValuePair<RemoteGameComponent, RemoteGamePropertyChanges>> GetEnumerator()
			{
				return _dictionary.GetEnumerator();
			}
		#endregion

		#region _GetOrCreateValue
			internal RemoteGamePropertyChanges _GetOrCreateValue(RemoteGameComponent component)
			{
				RemoteGamePropertyChanges changes;
				if (_dictionary.TryGetValue(component, out changes))
					return changes;

				changes = new RemoteGamePropertyChanges();
				_dictionary.Add(component, changes);
				return changes;
			}
		#endregion
		#region _RemoveEmptyChanges
			internal void _RemoveEmptyChanges()
			{
				List<RemoteGameComponent> toRemove = null;
				foreach(var pair in _dictionary)
				{
					var component = pair.Key;
					var changes = pair.Value;

					if (changes.Count > 0)
						component.OnChanged(changes);
					else
					{
						if (toRemove == null)
							toRemove = new List<RemoteGameComponent>();

						toRemove.Add(component);
					}
				}

				if (toRemove != null)
					foreach(var component in toRemove)
						_dictionary.Remove(component);
			}
		#endregion

		#region IReadOnlyDictionary
			ICollection IReadOnlyDictionary.Keys
			{
				get
				{
					return _dictionary.Keys;
				}
			}

			ICollection IReadOnlyDictionary.Values
			{
				get
				{
					return _dictionary.Values;
				}
			}

			object IReadOnlyDictionary.this[object key]
			{
				get
				{
					return _dictionary[(RemoteGameComponent)key];
				}
			}

			bool IReadOnlyDictionary.ContainsKey(object key)
			{
				return ContainsKey((RemoteGameComponent)key);
			}

			bool IReadOnlyDictionary.ContainsValue(object value)
			{
				return ContainsValue((RemoteGamePropertyChanges)value);
			}

			bool IReadOnlyDictionary.TryGetValue(object key, out object value)
			{
				if (key == null)
					throw new ArgumentNullException("key");

				var component = key as RemoteGameComponent;
				if (component == null)
				{
					value = null;
					return false;
				}

				RemoteGamePropertyChanges changes;
				bool result = TryGetValue(component, out changes);
				value = changes;
				return result;
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return _dictionary.GetEnumerator();
			}
		#endregion
	}
}
